#include "intelligentresizeutility.h"


IntelligentResizeUtility::IntelligentResizeUtility(QImage *qin)
{

    pixelsGrid=new Pixel[qin->width()*qin->height()];
    this->height=qin->height();
    this->width=qin->width();
    //this->maxD=0;

    for (int i=0;i<qin->height();i++)
        for(int j=0;j<qin->width();j++){
           this->pixelsGrid[j+i*qin->width()]=Pixel(qin->pixel(j,i),j,i);

       }
    for (int i=1;i<qin->height()-1;i++)
        for(int j=1;j<qin->width()-1;j++){
           pixelsGrid[j+i*qin->width()].calculateD();
           if(pixelsGrid[j+i*qin->width()].getMaxD()>this->maxD)
               this->maxD=pixelsGrid[j+i*qin->width()].getMaxD();
       }
    for (int i=0;i<qin->height();i++)
        for(int j=0;j<qin->width();j++){
            pixelsGrid[j+i*qin->width()].calculateCost();
    }
}

QRgb Pixel::getRgb()
{

    return qRgb(this->color.red(),this->color.green(),this->color.blue());
}

void IntelligentResizeUtility::cutContour(QImage *qim){
    //cout<<"inside cutcontour"<<endl;

    for(int y=0;y<height;y++){
        QLinkedList<int> qll;
        for(int x=0;x<width;x++)
            qim->setPixel(x,y,qRgb(255,255,255));
        for(int x=0;x<width;x++)
        {
            //cout<<"SUM "<<sum<<endl;
            if(pixelsGrid[x+y*width].isContour()==true)
            {
                qll.append(x);
                while((pixelsGrid[x+1+y*width].isContour()==true))
                    x++;
            }
        }
        if(qll.size()%2==1)
            qll.removeLast();
        if(qll.size()>0)
        {
            while(qll.size()!=0)
            {
                int temp1=qll.first();
                qll.removeFirst();
                int temp2=qll.first();
                qll.removeFirst();
                //cout<<"Size"<<temp1<<" "<<temp2<<endl;
                for(int x=temp1;x<temp2;x++)
                {
                    qim->setPixel(x,y,pixelsGrid[x+y*width].getRgb());
                    //if(qRed(qim->pixel(x,y))==255&&qGreen(qim->pixel(x,y))==255&&qBlue(qim->pixel(x,y))==255)
                      //  qim->setPixel(x,y,qim->pixel(x,y-1));
                }

            }
        }
    }

    for(int x=0;x<width;x++)
    {
        QLinkedList<int> qll;
        for(int y=0;y<height;y++)
        {
            if(pixelsGrid[x+y*width].isContour()==true)
            {
                qll.append(y);
                while((pixelsGrid[x+(y+1)*width].isContour()==true))
                    y++;
            }
        }

        if(qll.size()%2==1)
            qll.removeLast();
        if(qll.size()>0)
        {
            while(qll.size()!=0)
            {
                int temp1=qll.first();
                qll.removeFirst();
                int temp2=qll.first();
                qll.removeFirst();
                //cout<<"Size"<<temp1<<" "<<temp2<<endl;
                for(int y=temp1;y<temp2+1;y++)
                    if(qRed(qim->pixel(x,y))==255&&qGreen(qim->pixel(x,y))==255&&qBlue(qim->pixel(x,y))==255)
                        qim->setPixel(x,y,pixelsGrid[x+y*width].getRgb());
                      //  qim->setPixel(x,y,qim->pixel(x,y-1));


            }

        }

    }
}




void Pixel ::setSeed(bool b)
{
    this->seed=b ;

}
double Pixel::getMaxD()
{
 return this->maxD;
}


Pixel ::Pixel(QRgb rgb,int x,int y)
{

    this->setColor(rgb);
    setX(x);
    setY(y);
    this->pixelState= INITIALIZED;
    this->next = NULL;
    this->seed= false ;    
    this->updateRGB();
    this->neighbor=new struct Neighbor[8];
    this->setContour(false);

}
Pixel::Pixel()
{

}
void Pixel::updateRGB()
{
    this->red= this->color.red();
    this->green= this->color.green();
    this->blue= this->color.blue();
}
bool Pixel ::isSeed()
{
    if(this->isSeed())
        return true;
    return false ;
}
void Pixel:: setColor(QRgb rgb)
{
    this->color = QColor ::fromRgb(rgb);
}
Pixel* Pixel::getNext()
{
    return this->next;
}
void Pixel::setNext(Pixel *next)
{
    this->next=next;
}
NODE_TYPE Pixel::getPixelState()
{
    return this->pixelState;
}
void Pixel::setPixelState(NODE_TYPE state)
{
    this->pixelState=state;
}

void Pixel::getNeighbors()
{
    int width=IntelligentResizeUtility::width;
    //cout<<"The value of X is : "<<x<<" The Value of y is  "<<y<<endl;
    if((x!=0)&&(y!=0)&&(x!=(unsigned int)width)&&(y!=(unsigned int)IntelligentResizeUtility::height))
 {
    neighbor[RIGHT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x+1)+y*width]);
    neighbor[UPPER_RIGHT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x+1)+(y-1)*width]);
    neighbor[UPPER].pixel=&(IntelligentResizeUtility::pixelsGrid[(x)+(y-1)*width]);
    neighbor[UPPER_LEFT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x-1)+(y-1)*width]);
    neighbor[LEFT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x-1)+(y)*width]);
    neighbor[LOWER_LEFT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x-1)+(y+1)*width]);
    neighbor[LOWER].pixel=&(IntelligentResizeUtility::pixelsGrid[(x)+(y+1)*width]);
    neighbor[LOWER_RIGHT].pixel=&(IntelligentResizeUtility::pixelsGrid[(x+1)+(y+1)*width]);
    // cout <<"And the Color is :"<<neighbor[LEFT].pixel->color.red()<<endl;
   // cout <<"And the Color is :"<<neighbor[UPPER].pixel->color.red()<<endl;
}

}
void Pixel::calculateD()
{
    this->getNeighbors();
    this->maxD=0;    
    //cout<<"the red value is ";
    neighbor[RIGHT].costR=abs(neighbor[UPPER].pixel->color.red()+neighbor[UPPER_RIGHT].pixel->color.red()-neighbor[LOWER].pixel->color.red()-neighbor[LOWER_RIGHT].pixel->color.red())/4;
    neighbor[RIGHT].costG=abs(neighbor[UPPER].pixel->color.green()+neighbor[UPPER_RIGHT].pixel->color.green()-neighbor[LOWER].pixel->color.green()-neighbor[LOWER_RIGHT].pixel->color.green())/4;
    neighbor[RIGHT].costB=abs(neighbor[UPPER].pixel->color.blue()+neighbor[UPPER_RIGHT].pixel->color.blue()-neighbor[LOWER].pixel->color.blue()-neighbor[LOWER_RIGHT].pixel->color.blue())/4;
    neighbor[UPPER_RIGHT].costR=abs(neighbor[RIGHT].pixel->color.red()-neighbor[UPPER].pixel->color.red())/sqrt(2);
    neighbor[UPPER_RIGHT].costG=abs(neighbor[RIGHT].pixel->color.green()-neighbor[UPPER].pixel->color.green())/sqrt(2);
    neighbor[UPPER_RIGHT].costB=abs(neighbor[RIGHT].pixel->color.blue()-neighbor[UPPER].pixel->color.blue())/sqrt(2);
    neighbor[UPPER].costR=abs(neighbor[LEFT].pixel->color.red()+neighbor[UPPER_LEFT].pixel->color.red()-neighbor[RIGHT].pixel->color.red()-neighbor[UPPER_RIGHT].pixel->color.red())/4;
    neighbor[UPPER].costG=abs(neighbor[LEFT].pixel->color.green()+neighbor[UPPER_LEFT].pixel->color.green()-neighbor[RIGHT].pixel->color.green()-neighbor[UPPER_RIGHT].pixel->color.green())/4;
    neighbor[UPPER].costB=abs(neighbor[LEFT].pixel->color.blue()+neighbor[UPPER_LEFT].pixel->color.blue()-neighbor[RIGHT].pixel->color.blue()-neighbor[UPPER_RIGHT].pixel->color.blue())/4;
    neighbor[UPPER_LEFT].costR=abs(neighbor[LEFT].pixel->color.red()-neighbor[UPPER].pixel->color.red())/sqrt(2);
    neighbor[UPPER_LEFT].costG=abs(neighbor[LEFT].pixel->color.green()-neighbor[UPPER].pixel->color.green())/sqrt(2);
    neighbor[UPPER_LEFT].costB=abs(neighbor[LEFT].pixel->color.blue()-neighbor[UPPER].pixel->color.blue())/sqrt(2);
    neighbor[LEFT].costR=abs(neighbor[UPPER].pixel->color.red()+neighbor[UPPER_LEFT].pixel->color.red()-neighbor[LOWER].pixel->color.red()-neighbor[LOWER_LEFT].pixel->color.red())/4;
    neighbor[LEFT].costG=abs(neighbor[UPPER].pixel->color.green()+neighbor[UPPER_LEFT].pixel->color.green()-neighbor[LOWER].pixel->color.green()-neighbor[LOWER_LEFT].pixel->color.green())/4;
    neighbor[LEFT].costB=abs(neighbor[UPPER].pixel->color.blue()+neighbor[UPPER_LEFT].pixel->color.blue()-neighbor[LOWER].pixel->color.blue()-neighbor[LOWER_LEFT].pixel->color.blue())/4;
    neighbor[LOWER_LEFT].costR=abs(neighbor[LEFT].pixel->color.red()-neighbor[LOWER].pixel->color.red())/sqrt(2);
    neighbor[LOWER_LEFT].costG=abs(neighbor[LEFT].pixel->color.green()-neighbor[LOWER].pixel->color.green())/sqrt(2);
    neighbor[LOWER_LEFT].costB=abs(neighbor[LEFT].pixel->color.blue()-neighbor[LOWER].pixel->color.blue())/sqrt(2);
    neighbor[LOWER].costR=abs(neighbor[LEFT].pixel->color.red()+neighbor[LOWER_LEFT].pixel->color.red()-neighbor[RIGHT].pixel->color.red()-neighbor[LOWER_RIGHT].pixel->color.red())/4;
    neighbor[LOWER].costG=abs(neighbor[LEFT].pixel->color.green()+neighbor[LOWER_LEFT].pixel->color.green()-neighbor[RIGHT].pixel->color.green()-neighbor[LOWER_RIGHT].pixel->color.green())/4;
    neighbor[LOWER].costB=abs(neighbor[LEFT].pixel->color.blue()+neighbor[LOWER_LEFT].pixel->color.blue()-neighbor[RIGHT].pixel->color.blue()-neighbor[LOWER_RIGHT].pixel->color.blue())/4;
    neighbor[LOWER_RIGHT].costR=abs(neighbor[RIGHT].pixel->color.red()-neighbor[LOWER].pixel->color.red())/sqrt(2);
    neighbor[LOWER_RIGHT].costG=abs(neighbor[RIGHT].pixel->color.green()-neighbor[LOWER].pixel->color.green())/sqrt(2);
    neighbor[LOWER_RIGHT].costB=abs(neighbor[RIGHT].pixel->color.blue()-neighbor[LOWER].pixel->color.blue())/sqrt(2);
    for(int i=RIGHT;i<=LOWER_RIGHT;i++)
    {
        neighbor[i].D= sqrt(neighbor[i].costR*neighbor[i].costR+neighbor[i].costG*neighbor[i].costG+neighbor[i].costB*neighbor[i].costB)/3;
        if(neighbor[i].D>maxD)
        {
            maxD= neighbor[i].D;
        }
    }
}

void Pixel::calculateCost(){
    for(int i=RIGHT;i<=LOWER_RIGHT;i++)
    {
        int length;
        if(i==RIGHT || i==LEFT || i==UPPER || i== LOWER)
            length=1;
        else
            length=sqrt(2);
        neighbor[i].cost=(IntelligentResizeUtility::maxD-neighbor[i].D)*length;

    }

}
void IntelligentResizeUtility::dijkstra(Pixel* seed)
{
    //cout<<"seed xy"<<seed.getX()<<" "<<seed.getY()<<endl;
    pixelsGrid[seed->getX()+seed->getY()*width].setSeed(true);
    distance=new double[width*height];
    for(int x=0;x<width*height;x++)
    {
        distance[x]=-1;        
    }
    distance[seed->getX()+seed->getY()*width]=0;

    PixelQueue.append(seed);
//    Pixel tempPixel = PixelQueue.first();
  //  cout <<"These are the Value of tempPixel : X,Y.red :"<<tempPixel.getX()<<tempPixel.getY()<<endl;

    while(!PixelQueue.isEmpty())
    {
        Pixel *q;
        Pixel *temp;
        int min_q=INT_MAX;
        foreach(temp,PixelQueue){
            if((distance[temp->getX()+temp->getY()*width]<min_q)&&(temp->getX()>0)&&(temp->getX()<(unsigned int)IntelligentResizeUtility::width-1)&&(temp->getY()>0)&&(temp->getY()<(unsigned int)IntelligentResizeUtility::height-1)){
                q=temp;
                min_q=distance[temp->getX()+temp->getY()*width];
            }
     //     cout<<"x,y"<<temp->getX()<<" "<<temp->getY()<<endl;
        }

        q->setPixelState(EXPANDED);

        for(int i=0;i<=7;i++)
        {
            //cout<<"i is"<< i<<endl;
            Pixel *r=(q->neighbor[i].pixel);
           // cout<<"hi"<< i<<endl;
            if(r->getPixelState()!=EXPANDED)
            {
                if(r->getPixelState()==INITIALIZED)
                {                    
                r->setNext(q);
                distance[r->getX()+r->getY()*width]=distance[q->getX()+q->getY()*width]+q->neighbor[i].cost;
                r->setPixelState(ACTIVE);
                if(r->getX()==0||r->getY()==0||r->getX()==(unsigned int)(width-1)||r->getY()==(unsigned int)(height-1))
                    continue;
                PixelQueue.append(r);;

                }
                else if(r->getPixelState()==ACTIVE)
                {
                    if(distance[q->getX()+q->getY()*width]+q->neighbor[i].cost<distance[r->getX()+r->getY()*width])
                    {
                        r->setNext(q);
                        distance[r->getX()+r->getY()*width]=distance[q->getX()+q->getY()*width]+q->neighbor[i].cost;
                    }
                }
            }
        }
        PixelQueue.removeOne(q);
        //cout<< "The Size of the Pixel Que is "<< PixelQueue.size()<<endl;
        //cout<<"end of one round"<<endl;

    }
           delete [] distance;
}
bool Pixel::operator== (const Pixel & other ) const
{
    bool xyBool =(this==&other);
    return xyBool;
}

void IntelligentResizeUtility::tracePath(Pixel *pixelStart, Pixel *pixelEnd, QLinkedList<QPoint>* path)
{

    this->dijkstra(pixelStart,pixelEnd);
    Pixel *tempPixel=pixelEnd ;

    while(//(tempPixel!=NULL)
        //&&
        (tempPixel->getNext()!=NULL)
        &&
        !((tempPixel->getX()==pixelStart->getX())&&(tempPixel->getY()==pixelStart->getY())))
    {

            //cout <<"Inside while X :"<<tempPixel->getX()<<"Y :"<<tempPixel->getY()<<endl;
            Pixel *nexT=tempPixel->getNext();
            this->pathList.append(*nexT);
       //cout <<"Trace Path"<<endl;
            QPoint qp_temp=QPoint(tempPixel->getX(),tempPixel->getY());
            path->append(qp_temp);
//////////
            /*
            int temp_x=tempPixel->getX();
            int temp_y=tempPixel->getY();
            for(int i=0;i<=7;i++)
            {
                tempPixel->neighbor[i].cost=tempPixel->neighbor[i]  .cost*100;
                if(i<4)
                    tempPixel->neighbor[i].pixel->neighbor[i+4].cost=tempPixel->neighbor[i].pixel->neighbor[i+4].cost*100;
                else
                    tempPixel->neighbor[i].pixel->neighbor[i-4].cost=tempPixel->neighbor[i].pixel->neighbor[i-4].cost*100;
            }*/
/////////
            tempPixel= tempPixel->getNext();
    }
    //cout <<"Outside while X :"<<tempPixel->getX()<<"Y :"<<tempPixel->getY()<<endl;

    for(int i=0;i<height*width;i++){
        pixelsGrid[i].setNext(NULL);
        pixelsGrid[i].setPixelState(INITIALIZED);
    }

}
Pixel* IntelligentResizeUtility::retrivePixel(unsigned int x, unsigned int y)
{
    return &(pixelsGrid[x+y*IntelligentResizeUtility::width]);
}

unsigned int Pixel ::getX()
{
    return this->x;

}
unsigned int Pixel::getY()
{
    return this->y;
}
void Pixel::setX(unsigned int x)
{
    this->x=x;
}
void Pixel::setY(unsigned int y)
{
    this->y=y;
}
void IntelligentResizeUtility::dijkstra(Pixel* seed, Pixel * finalSeed)
{    
    pixelsGrid[seed->getX()+seed->getY()*width].setSeed(true);
    PixelQueue.clear();
    //cout<<"Queue size"<<PixelQueue.size();
    distance=new double[width*height];
    for(int x=0;x<width*height;x++)
    {
        distance[x]=-1;
    }
    distance[seed->getX()+seed->getY()*width]=0;
    //cout<<"seed"<<seed->getX()<<" "<<seed->getY();
    //cout<<"finalseed"<<finalSeed->getX()<<" "<<finalSeed->getY();
    PixelQueue.append(seed);
    while(!PixelQueue.isEmpty())
    {
        Pixel *q;
        Pixel *temp;
        int min_q=INT_MAX;
        foreach(temp,PixelQueue){
            if((distance[temp->getX()+temp->getY()*width]<min_q)&&(temp->getX()>0)&&(temp->getX()<(unsigned int)(IntelligentResizeUtility::width-1))&&(temp->getY()>0)&&(temp->getY()<(unsigned int)(IntelligentResizeUtility::height-1))){
                q=temp;
                min_q=distance[temp->getX()+temp->getY()*width];
            }
     //     cout<<"x,y"<<temp->getX()<<" "<<temp->getY()<<endl;
        }
        if(q==finalSeed)
            break ;

        q->setPixelState(EXPANDED);
        //cout<<"Q is "<<q->getX()<<" "<<q->getY()<<endl;
        for(int i=0;i<=7;i++)
        {

            Pixel *r=(q->neighbor[i].pixel);        
            if(r->getPixelState()!=EXPANDED)
            {
                if(r->getPixelState()==INITIALIZED)
                {
                r->setNext(q);
                //cout<<"R is "<<r->getX()<<" "<<r->getY()<<endl;
                distance[r->getX()+r->getY()*width]=distance[q->getX()+q->getY()*width]+q->neighbor[i].cost;
                r->setPixelState(ACTIVE);
                if(r->getX()==0||r->getY()==0||r->getX()==(unsigned int)(width-1)||r->getY()==(unsigned int)(height-1))
                    continue;
                PixelQueue.append(r);
                }
                else if(r->getPixelState()==ACTIVE)
                {
                    if(distance[q->getX()+q->getY()*width]+q->neighbor[i].cost<distance[r->getX()+r->getY()*width])
                    {
                        r->setNext(q);
                        //
                        distance[r->getX()+r->getY()*width]=distance[q->getX()+q->getY()*width]+q->neighbor[i].cost;
                    }
                }
            }
        }
        PixelQueue.removeOne(q);
     //   cout<< "The Size of the Pixel Que is "<< PixelQueue.size()<<endl;

    }
    delete [] distance;
}
void Pixel ::setContour(bool isContour)
{
    this->contour=isContour;
}
bool Pixel::isContour()
{
    return this->contour;
}

Pixel *IntelligentResizeUtility::pixelsGrid=NULL;
int IntelligentResizeUtility::width=0;
int IntelligentResizeUtility::height=0;
double  IntelligentResizeUtility::maxD=0.0;
//IntelligentResizeUtility::IntelligentResizeUtility(){

//}
IntelligentResizeUtility::~IntelligentResizeUtility(){
    for (int i=0;i<height*width;i++)
        delete [] pixelsGrid[i].neighbor;
    delete [] pixelsGrid;
}
